# (c) https://github.com/MontiCore/monticore

#
# This makefile demonstrates how to embedd a MontiCore
# code generation and a tool execution in a
# makefile using make for efficient incremental generation
#
  # Efficient == only do what is needed; but fully automatic
  # Incremental == makefile itself checks whether to regenerate
  # and therefore uses MontiCore's IncGenCheck.sh
  #
  # It is somewhat lengthy, because it explains a lot
  #

  ##############################################    Explanations
  # The makefile handles two levels of generation and processing
  # Level
  #   M2: MontiCore LWB generates Automata tool-code
  #        & compiles & jars it
  #   M1: The resulting Automata tool is tested
  #       and executed on real automata
  #
  # Using many default configurations, it is mainly the
  # grammar name that needs to be configured here
  # and of course the individual tool calls:
  # This means there are two parts to be configured,
  # while the rest is generic.
  #
  #

#############################################################
# Configuration (files and used commands):

# Individual Configuration:       <<-- adapt this part

# M2-model to be processed (the grammar)
GRAMMAR=src/main/grammars/Automata.mc4

# -->> end of adapting part 1 (of 2)

#############################################################
# Configuration B: the generic part
# (which needs normally not be touched)

# a few things are derived from the grammar name
GramNameCap=$(patsubst src/main/grammars/%.mc4,%,$(GRAMMAR))
GramName=$(shell echo $(GramNameCap) | tr '[:upper:]' '[:lower:]')

# path for the generated sources
GenSrc=target/$(GramName)

# name of resulting tool and its main class:
Tool=target/$(GramNameCap)Tool.jar
ToolClass=$(GramName).$(GramNameCap)Tool

# M2+M1-input: All handwritten sources (from M1) for the tool
  # this is needed on M2 level to apply the TOP mechanism
SRC=$(wildcard src/main/**/$(GramName)/*java)
TESTSRC=$(wildcard src/test/**/$(GramName)/*java)

# foreign jars for testing
JUNIT=target/junit-4.12.jar
HAMCREST=target/hamcrest-core-1.3.jar

# jars for the MontiCore call (M2), runtime (M1+M2), and grammars (M2)
MCJAR=target/monticore-cli.jar
MCRTE=target/monticore-rt.jar


# initialization flag
InitTarget=target/init.f

# starting rule
all: testsAndExecution


#############################################################
# Usage Activities (M1): processing Models:
# Each is handling one automaton (producing one file)
  #
  # Because in these executions there is no additional (optional) input
  # needed, we do not need to use an IncGenCheck for these tool executions.

# <<-- adapt this part
$(GenSrc)-executes.f: target/PingPong.result \
                      target/HierarchyPingPong.result \
		      target/Simple12.result
	@echo "[MINFO]. 6c: Showing some results for:" $<
	@cat target/Simple12.result
	@echo "[MINFO]. 6c: End of results."
	@touch $@

# specific goal: applying the generated tool on a model
target/PingPong.result: src/test/resources/example/PingPong.aut \
                        $(Tool) $(MCRTE)
	@echo "[MINFO]. 6a: Handling" $<
	java -cp "$(Tool);$(MCRTE)" \
	     $(ToolClass) $< $(patsubst $@,%.result,%.sym) > $@

target/HierarchyPingPong.result: \
                        src/test/resources/example/HierarchyPingPong.aut \
                        $(Tool) $(MCRTE)
	@echo "[MINFO]. 6b: Handling" $<
	java -cp "$(Tool);$(MCRTE)" \
	     $(ToolClass) $< $(patsubst $@,%.result,%.sym) > $@

target/Simple12.result: src/test/resources/example/Simple12.aut \
                        $(Tool) $(MCRTE)
	@echo "[MINFO]. 6c: Handling" $<
	java -cp "$(Tool);$(MCRTE)" \
	     $(ToolClass) $< $(patsubst $@,%.result,%.sym) > $@

# -->> end of adapting part 2 (of 2)

#############################################################
# Start of generic rule part B (which needs normally not be touched)

# initial rule describing all relevant sub-activities

testsAndExecution: $(GenSrc)-tests.f  $(GenSrc)-executes.f
	@echo "[MINFO]. Done with" $@"."

  ##############################################    Explanations
  # make normally uses real files as goal of a rule,
  # sometimes dummy goals, such as "automata.f" help to
  # to ensure that the action is atomic
  # (e.g. it may happen that the directory "automata" is created,
  # but only half of the files: the flag "automata.f" is
  # touched only if the creation was complete and successful)

#############################################################
# Generate and compile (M2):

  ##############################################    Explanations
  # The MontiCore generator has some explicitely known inputs, such as
  # the $(GRAMMAR), but the TOP mechanism adds additional implicit inputs.
  # The IncGenCheck.sh is generated by MontiCore and knows these
  # dependencies. It is included as follows:
  # goal incGenStamp.f must always be executed newly (because of
  # the force); this executes IncGenCheck.sh, which updates the
  # timestamp of incGenStamp.f if needed, which triggers a
  # regeneration of $(GenSrc).f

# Check dependencies for $(GRAMMAR)
$(GenSrc).incGenStamp.f: $(InitTarget) force
	@echo "[MINFO]. 1: Check if generation for \"" $(GramName)"\" is needed?"
	@[ -e $@ ] || touch $@
	@[ -e $(GenSrc)/IncGenCheck.sh ] \
	  && sh $(GenSrc)/IncGenCheck.sh $@ || true

# Activity 1 (M2): run MontiCore generator for $(GRAMMAR)
$(GenSrc).f: $(GRAMMAR) $(MCJAR) $(MCRTE) \
                        $(GenSrc).incGenStamp.f
	@echo "[MINFO]. 1: Generation of tool code from" $(GRAMMAR)
	java -jar $(MCJAR) \
		-g $(GRAMMAR) \
		-mp $(MCRTE) \
		-hcp src/main/java \
		-out target
	@touch $@

  ##############################################    Explanations
  # This can be tested, e.g.
  # make
  # find . -name "ASTStateTOP*"
  #     -> finds 2 files
  # mv ./src/main/java/automata/_ast/ASTState.java xtemporary
  # make
  # find . -name "ASTStateTOP*"
  #     -> empty
  # mv xtemporary ./src/main/java/automata/_ast/ASTState.java
  # make
  # find . -name "ASTStateTOP*"
  #     -> finds again 2 files
  #

# Activity 2 (M2): compile the tool
$(GenSrc)-classes.f: $(GenSrc).f $(SRC) $(MCRTE)
	@echo "[MINFO]. 2: Compile tool:" $(GenSrc)-classes
	@mkdir -p $(GenSrc)-classes/
	javac -cp $(MCRTE) \
	      -d $(GenSrc)-classes/ \
	      -sourcepath "target/;src/main/java/" \
	      src/main/java/$(GramName)/$(GramNameCap)Tool.java
	@touch $@

# Activity 3 (M2): build the tool jar
$(Tool): $(GenSrc)-classes.f
	@echo "[MINFO]. 3: Create tool jar:" $<
	jar cfe $(Tool) $(GramName).$(GramNameCap)Tool \
	    -C $(GenSrc)-classes .

#############################################################
# Testing (M2 and M1)

TESTSRC=$(wildcard src/test/**/$(GramName)/*java)
TESTCLASSES=$(patsubst $(GenSrc)-testclasses/$(GramName)/%.class,$(GramName).%,$(wildcard $(GenSrc)-testclasses/$(GramName)/*Test.class))

# Activity 4 (M2): compile the tests
# (which was on purpose not integrated in tool compilation)
$(GenSrc)-testclasses.f: $(Tool) $(SRC) $(MCRTE) $(JUNIT)
	@echo "[MINFO]. 4: Compile tests in" $(GenSrc)-testclasses
	@mkdir -p $(GenSrc)-testclasses/
	javac -cp "$(Tool);$(MCRTE);$(JUNIT)" \
	      -d $(GenSrc)-testclasses/ \
	      -sourcepath "target/;src/test/java/" \
	      $(TESTSRC)
	@touch $@

# Activity 5 (M1): execute the tests
$(GenSrc)-tests.f: $(GenSrc)-testclasses.f $(JUNIT) $(HAMCREST)
	@echo "[MINFO]. 5: Run tests in" $(GenSrc)-testclasses
	@java  -cp \
	  "$(GenSrc)-testclasses;$(Tool);$(MCRTE);$(JUNIT);$(HAMCREST)" \
	       org.junit.runner.JUnitCore \
	       $(TESTCLASSES)
	@touch $@

#############################################################
# Auxiliary

# The following simplified version does not manage updates
# of foreign libaries

# Initialize target directory
$(InitTarget):
	mkdir -p target
	@touch $@

# position the MontiCore LWB; MontiCore RTE; MontiCore base grammars
# (alternatively it is possible to use wget for a download
#  of the jars from nexus, see e.g. reference manual)
$(MCJAR): $(InitTarget)
	wget https://monticore.de/download/monticore-cli.jar
	mv monticore-cli.jar target

$(MCRTE): $(InitTarget)
	wget https://monticore.de/download/monticore-rt.jar
	mv monticore-rt.jar target

# get the testing libraries
$(JUNIT): $(InitTarget)
	wget -O $(JUNIT) "https://nexus.se.rwth-aachen.de/service/rest/v1/search/assets/download?repository=public&maven.groupId=junit&maven.artifactId=junit&maven.extension=jar&maven.baseVersion=4.13.1&maven.classifier="

$(HAMCREST): $(InitTarget)
	wget -O $(HAMCREST) "https://nexus.se.rwth-aachen.de/service/rest/v1/search/assets/download?repository=public&maven.groupId=org.hamcrest&maven.artifactId=hamcrest-core&maven.extension=jar&maven.baseVersion=1.3&maven.classifier="

clean:
	rm -rf target

.PHONY: clean force


